Dynomotion

Group: DynoMotion Message: 5331 From: erry321 Date: 6/26/2012
Subject: MPG question
Hello Tom

I am trying to connect the MPG to the controller.
The MPG is weird one with very narrow AB pulses, so I have to use one of the axis encoders to read the MPG. The encoder input works perfectly.
So, this is the code I am using to create spindle PWM and read encoder:

for (;;) //loop forever
{
WaitNextTimeSlice();
T=T+1;

float LastState = persist.UserData[98]; // get last state


if (chan[5].Enable) // is the axis enabled??

{

SetBit(27);
NewOutput = chan[5].Output;


if (NewOutput<0)
{
NewOutput=-NewOutput;


SetBit(28); // Set the reverse

}

else

{
ClearBit(28);
}

FPGA(IO_PWMS+0) = NewOutput+32;

}


else
{
FPGA(IO_PWMS+0) = 32; // whenever not enabled put to 0 RPM
ClearBit(27); // all off
ClearBit(28);

}


// MPG processing
if (T>10)
{

Mpg_Pos_Current = ch6->Position;

if (ReadBit(19)) // is X1 selected?
Factor = 0.1;
else if (ReadBit(20)) // is X10 selected?
Factor = 1;
else if (ReadBit(21)) // is X50 selected?
Factor = 10;
else Factor = 0;

if (ReadBit(14)) // if the button pressed ignore the encoder.
Mpg_Pos_Current = 0;

Mpg_Pos_Change = Mpg_Pos_Current;
Mpg_Pos_Change_Final = Mpg_Pos_Change*Factor;


if (ReadBit(16)) // is x selected?
ch0->Dest -=Mpg_Pos_Change_Final;
else if (ReadBit(17)) // is y selected?
ch1->Dest -=Mpg_Pos_Change_Final;
else if (ReadBit(18)) // is z selected?
ch2->Dest +=Mpg_Pos_Change_Final;
T=0;
Zero(6);


}
}


So, if the Factor is 1, everything works well and position follows the destination even I spin the encoder up to ~600RPM with 0.1mm change in position for 1 revolution.
But if the Factor is 100, 50, or even 10, the position follows the destination within MaxI channel parameter and stops even I barely spin the encoder (the position change is way lower than if I run it 600RPM with the Factor = 1). So if I have MaxI set to 10000, the position would follow the destination till it reach ~10000 or ~-10000 and stop.
Nothing like that with the Factor = 1.

Everything else works well, I able to run CL Steppers with the feed rate as high as 84IPM, no position errors.

I can not figure out what is going on. Is it some limitations on how much the destination can be changed in one step?
I would like to run the MPG with the Factor at least 10 to be comfortable.

Below is the one axis configuration for an example:

ch0->InputMode=ENCODER_MODE;
ch0->OutputMode=CL_STEP_DIR_MODE;
ch0->Vel=60000;
ch0->Accel=4e+006;
ch0->Jerk=4e+007;
ch0->P=0.0035;
ch0->I=0.004;
ch0->D=0.001;
ch0->FFAccel=0;
ch0->FFVel=0;
ch0->MaxI=10000;
ch0->MaxErr=1e+009;
ch0->MaxOutput=200;
ch0->DeadBandGain=1;
ch0->DeadBandRange=0;
ch0->InputChan0=0;
ch0->InputChan1=0;
ch0->OutputChan0=8;
ch0->OutputChan1=0;
ch0->MasterAxis=-1;
ch0->LimitSwitchOptions=0x0;
ch0->InputGain0=-5; // encoder resolution 100ppr, 10 microSteps mode
ch0->InputGain1=1;
ch0->InputOffset0=0;
ch0->InputOffset1=0;
ch0->OutputGain=1;
ch0->OutputOffset=0;
ch0->SlaveGain=1;
ch0->BacklashMode=BACKLASH_OFF;
ch0->BacklashAmount=0;
ch0->BacklashRate=0;
ch0->invDistPerCycle=10;
ch0->Lead=0;
ch0->MaxFollowingError=500;
ch0->StepperAmplitude=20;

ch0->iir[0].B0=0.000768809;
ch0->iir[0].B1=0.00153762;
ch0->iir[0].B2=0.000768809;
ch0->iir[0].A1=1.92081;
ch0->iir[0].A2=-0.923885;

ch0->iir[1].B0=1;
ch0->iir[1].B1=0;
ch0->iir[1].B2=0;
ch0->iir[1].A1=0;
ch0->iir[1].A2=0;

ch0->iir[2].B0=1;
ch0->iir[2].B1=0;
ch0->iir[2].B2=0;
ch0->iir[2].A1=0;
ch0->iir[2].A2=0;

I think somebody mention already rough behavior of the MPG before.

Best regards,
Alexey
Group: DynoMotion Message: 5333 From: Tom Kerekes Date: 6/26/2012
Subject: Re: MPG question
Hi Alexey,
 
Yes I believe the problem is because it is trying to make too big and sudden steps.  For example if the Dest is all of a sudden changed by 100 microsteps then KFLOP will output pulses at a high rate (over 1 MHz)  to be at the desired destination by the next 90us servo sample time.  This most likely stalls your stepper motor and results in no or little actual motion (or actually unless the step pulse is set really short pulses at this rate would be overlapped into one big pulse).  Because you are running closed loop the Servo loop detects that the encoder indicates that the motor is at the wrong position due to lost steps.  It then makes a gradual output correction based on the Integrator Rate.  Once the Integrator has made the maximum allowed amount of correction (MaxI) further errors will then go uncorrected.
 
Instead of changing the Dest directly in steps try using the MoveExp() command to move.   This will essentially low pass filter the big commanded steps into smoother motion distributed over many servo samples.  The Time Constant Tau can be adjusted to apply more or less smoothing (and consequently more or less lag).  See the MPGSmooth.c for an example.
 
Regards
TK
 
 
 
 
 
 
 
 

Group: DynoMotion Message: 5334 From: erry321 Date: 6/26/2012
Subject: Re: MPG question
Thanks Tom

I have come up with the following code:

for (;;) //loop forever
{
WaitNextTimeSlice();
T=T+1;

float LastState = persist.UserData[98]; // get last state


if (chan[5].Enable) // is the axis enabled??

{

SetBit(27);
NewOutput = chan[5].Output;


if (NewOutput<0)
{
NewOutput=-NewOutput;


SetBit(28);

}

else

{
ClearBit(28);
}

FPGA(IO_PWMS+0) = NewOutput+32;

}


else
{
FPGA(IO_PWMS+0) = 32; // whenever not enabled put to 0 RPM
ClearBit(27); // all off
ClearBit(28);

}


// MPG processing
if (T>10)
{
Mpg_Pos_Current = ch6->Position;
X_Pos_Current = ch0->Position;
Y_Pos_Current = ch1->Position;
Z_Pos_Current = ch2->Position;

if (ReadBit(19)) // is X1 selected?
{
Factor = 2;
TAU=0.01;
}
else if (ReadBit(20)) // is X10 selected?
{
Factor = 20;
TAU=0.03;
}
else if (ReadBit(21)) // is X100 selected?
{
Factor = 200;
TAU=0.05;
}
else Factor = 0;

if (ReadBit(14)) // if button pressed ignore the encoder.
Mpg_Pos_Current = 0;

Mpg_Pos_Change = Mpg_Pos_Current;
Mpg_Pos_Change_Final = Mpg_Pos_Change*Factor;


if (ReadBit(16)) // is x selected?
{
MoveExp(0,X_Pos_Current-Mpg_Pos_Change_Final,TAU);
while (CheckDone(0));
}
else if (ReadBit(17)) // is y selected?
{
MoveExp(1,Y_Pos_Current-Mpg_Pos_Change_Final,TAU);
while (CheckDone(1));
}
else if (ReadBit(18)) // is z selected?
{
MoveExp(2,Z_Pos_Current+Mpg_Pos_Change_Final,TAU);
while (CheckDone(2));
}
T=0;
Zero(6);

}

}

The only issue with MoveExp, you can not be sure what every turn would give you the same movement, so I can not rely on the MPG ring scale and have to watch the coordinates on the screen all the time.
Group: DynoMotion Message: 5342 From: Tom Kerekes Date: 6/26/2012
Subject: Re: MPG question
Hi Alexey,
 
That is because of the way you wrote the progam it doesn't really have anything to do with the MoveExp() function.  Your program essentially makes a new relative move while the motion is still in progress so the total amount of motion will be unpredictable.  I think a better way is to maintain an absolute "target" position that is driven more directly from the encoder motion like the original MPGSmooth.c.  I've tried to modify the MPGSmooth.c program to use a Hardware Encoder input and changed it for your input bits.  See the attached MPGSMoothHardwareEnc.c.  Please try that.  It isn't tested :}
 
On a minor note:  The MoveExp() command never completes.  It converges forever.  That is why the program is written to detect no encoder motion for 1 sec and then do a final move of the last little bit.  The logic for your
 
while (CheckDone(0))  ;
 
was backwards so it never waited at all.
 
Hope this works better.
TK
 
 

Group: DynoMotion Message: 5347 From: Alexey Volkov Date: 6/26/2012
Subject: Re: MPG question [1 Attachment]
Hello Tom

It works perfectly, thanks a lot! 
The only thing I had to modify is the direction control:I need  X and Y going in negative direction and Z in positive.

if (ReadBit(SELECTX))  // is x selected?
{
Axis=0;
Dir=-1;
}
else if (ReadBit(SELECTY))  // is y selected?
{
Axis=1;
Dir=-1;
}
else if (ReadBit(SELECTZ))  // is z selected?
{
Axis=2;
Dir=1;
}

// check if the Axis just changed or we have been 
// converging to the target for a long time
if (Axis != LastAxis || 
(InMotion && Time_sec() > LastChangeTime+FINAL_TIME))
{
if (InMotion)
Move(LastAxis,Target);  //finalize any motion
LastAxis = Axis;
InMotion = FALSE;
}
if (Change1) // did we move?
{
if (!InMotion) Target = chan[Axis].Dest;
Target += Change1 * Factor*Dir;
MoveExp(Axis,Target,TAU);  // note: contains a WaitNextTimeSlice
LastChangeTime = Time_sec();
InMotion=TRUE;
}

Best regards,
Alexey 

On Tue, Jun 26, 2012 at 8:13 PM, Tom Kerekes <tk@...> wrote:
 
[Attachment(s) from Tom Kerekes included below]

Hi Alexey,
 
That is because of the way you wrote the progam it doesn't really have anything to do with the MoveExp() function.  Your program essentially makes a new relative move while the motion is still in progress so the total amount of motion will be unpredictable.  I think a better way is to maintain an absolute "target" position that is driven more directly from the encoder motion like the original MPGSmooth.c.  I've tried to modify the MPGSmooth.c program to use a Hardware Encoder input and changed it for your input bits.  See the attached MPGSMoothHardwareEnc.c.  Please try that.  It isn't tested :}
 
On a minor note:  The MoveExp() command never completes.  It converges forever.  That is why the program is written to detect no encoder motion for 1 sec and then do a final move of the last little bit.  The logic for your
 
while (CheckDone(0))  ;
 
was backwards so it never waited at all.
 
Hope this works better.
TK
 
 

Group: DynoMotion Message: 9957 From: lovethebuzz69 Date: 8/12/2014
Subject: MPG question
Hi Folks,I humbly request your help getting my MPG to work. I just do not understand the C code enough to figure out what is happening. I have tried every way I can think of to get the Kflop/Kanalog combination to service the MPG.Using the MPGSmoothHardwareEnc.c example I modified the the code to match my configuration of the x axis  (ch1). The MPG is connected to the axis 7 encoder input of the Kanalog. The MPG generates counts that show up in the Axis screen under axis 7. In the code I set the MPG_INPUT_AXIS = 7 and the other defines to match the bits I am using for the SelectX, Y, and Z, and for the Factor1, 10 and 100.Any help would be greatly appreciated.Here is the code I am currently trying to use just to jog the X axis to start with. Hopefully from there I can figure out Y, Z, and A.ThanksRick#include "KMotionDef.h"// Example Init program that includes "smooth" MPG motion example// which makes use of the exponential motion command.#define MPG_INPUT_AXIS 7#define TAU 0.08 // smoothness factor (Low Pass Time constant seconds)#define FINAL_TIME 1.0 // Set final dest after this amount of time with no change#define ENABLE_MPG 140#define SELECTX 128#define SELECTY 129#define SELECTZ 130#define FACTOR1 131#define FACTOR10 132#define FACTOR100 133main(){    int Change1, NewPos, Pos;    int InMotion=FALSE,Axis,LastAxis=-1;    double LastChangeTime=0,Target,Factor=0;        ch1->InputMode=ENCODER_MODE;    ch1->OutputMode=DAC_SERVO_MODE;    ch1->Vel=40000;    ch1->Accel=400000;    ch1->Jerk=600000;    ch1->P=1;    ch1->I=0;    ch1->D=10;    ch1->FFAccel=0;    ch1->FFVel=0;    ch1->MaxI=2000;    ch1->MaxErr=1e+008;    ch1->MaxOutput=2000;    ch1->DeadBandGain=1;    ch1->DeadBandRange=0;    ch1->InputChan0=1;    ch1->InputChan1=1;    ch1->OutputChan0=1;    ch1->OutputChan1=1;    ch1->MasterAxis=-1;    ch1->LimitSwitchOptions=0x103;    ch1->LimitSwitchNegBit=136;    ch1->LimitSwitchPosBit=136;    ch1->SoftLimitPos=1e+009;    ch1->SoftLimitNeg=-1e+009;    ch1->InputGain0=1;    ch1->InputGain1=1;    ch1->InputOffset0=0;    ch1->InputOffset1=0;    ch1->OutputGain=1;    ch1->OutputOffset=0;    ch1->SlaveGain=1;    ch1->BacklashMode=BACKLASH_OFF;    ch1->BacklashAmount=0;    ch1->BacklashRate=0;    ch1->invDistPerCycle=1;    ch1->Lead=0;    ch1->MaxFollowingError=10000;    ch1->StepperAmplitude=250;    ch1->iir[0].B0=1;    ch1->iir[0].B1=0;    ch1->iir[0].B2=0;    ch1->iir[0].A1=0;    ch1->iir[0].A2=0;    ch1->iir[1].B0=1;    ch1->iir[1].B1=0;    ch1->iir[1].B2=0;    ch1->iir[1].A1=0;    ch1->iir[1].A2=0;    ch1->iir[2].B0=0.0166094;    ch1->iir[2].B1=0.0332189;    ch1->iir[2].B2=0.0166094;    ch1->iir[2].A1=1.60679;    ch1->iir[2].A2=-0.673229;        EnableAxisDest(1,0);            EnableAxisDest(1,ch1->Position);    DefineCoordSystem(1,-1,-1,-1);        Pos = chan[MPG_INPUT_AXIS].Position;    for (;;)    {        NewPos = chan[MPG_INPUT_AXIS].Position;        Change1 = NewPos - Pos;        Pos = NewPos;        if (ReadBit(ENABLE_MPG)) // if button pressed ignore the encoder.            Change1 = 0;        else if (ReadBit(FACTOR1))  // is X1 selected?            Factor = 2;        else if (ReadBit(FACTOR10))  // is X10 selected?            Factor = 20;        else if (ReadBit(FACTOR100))  // is X100 selected?            Factor = 200;        else                               Factor = 0.0;        if (ReadBit(SELECTX))  // is x selected?            Axis=0;        else if (ReadBit(SELECTY))  // is y selected?            Axis=1;        else if (ReadBit(SELECTZ))  // is z selected?            Axis=2;        // check if the Axis just changed or we have been         // converging to the target for a long time        if (Axis != LastAxis ||             (InMotion && Time_sec() > LastChangeTime+FINAL_TIME))        {            if (InMotion)                Move(LastAxis,Target);  //finalize any motion                LastAxis = Axis;            InMotion = FALSE;        }                if (Change1) // did we move?        {            if (!InMotion) Target = chan[Axis].Dest;            Target += Change1 * Factor;            MoveExp(Axis,Target,TAU);  // note: contains a WaitNextTimeSlice            LastChangeTime = Time_sec();            InMotion=TRUE;        }        else        {            WaitNextTimeSlice();        }            }        return 0;}

Group: DynoMotion Message: 9958 From: Tom Kerekes Date: 8/12/2014
Subject: Re: MPG question
Hi lovethebuzz69,

Your post is hard to read.

It seems your X axis is Axis 1.  Normally X would be Axis 0.

As coded to move Axis 1 SELECTY (Input bit 129) would need to be active.  Have you checked on the Digital IO Screen if 129 is checked? 

Also:

The ENABLE_MPG 140 must be unchecked
The SELECTX 128 must be unchecked
One of the FACTORS 131, 132, 133 must be checked.

Have you verified this?

Regards
TK



From: "lovethebuzz69@... [DynoMotion]" <DynoMotion@yahoogroups.com>
To: DynoMotion@yahoogroups.com
Sent: Tuesday, August 12, 2014 5:11 PM
Subject: [DynoMotion] MPG question

 
Hi Folks,I humbly request your help getting my MPG to work. I just do not understand the C code enough to figure out what is happening. I have tried every way I can think of to get the Kflop/Kanalog combination to service the MPG.Using the MPGSmoothHardwareEnc.c example I modified the the code to match my configuration of the x axis  (ch1). The MPG is connected to the axis 7 encoder input of the Kanalog. The MPG generates counts that show up in the Axis screen under axis 7. In the code I set the MPG_INPUT_AXIS = 7 and the other defines to match the bits I am using for the SelectX, Y, and Z, and for the Factor1, 10 and 100.Any help would be greatly appreciated.Here is the code I am currently trying to use just to jog the X axis to start with. Hopefully from there I can figure out Y, Z, and A.ThanksRick#include "KMotionDef.h"// Example Init program that includes "smooth" MPG motion example// which makes use of the exponential motion command.#define MPG_INPUT_AXIS 7#define TAU 0.08 // smoothness factor (Low Pass Time constant seconds)#define FINAL_TIME 1.0 // Set final dest after this amount of time with no change#define ENABLE_MPG 140#define SELECTX 128#define SELECTY 129#define SELECTZ 130#define FACTOR1 131#define FACTOR10 132#define FACTOR100 133main(){    int Change1, NewPos, Pos;    int InMotion=FALSE,Axis,LastAxis=-1;    double LastChangeTime=0,Target,Factor=0;        ch1->InputMode=ENCODER_MODE;    ch1->OutputMode=DAC_SERVO_MODE;    ch1->Vel=40000;    ch1->Accel=400000;    ch1->Jerk=600000;    ch1->P=1;    ch1->I=0;    ch1->D=10;    ch1->FFAccel=0;    ch1->FFVel=0;    ch1->MaxI=2000;    ch1->MaxErr=1e+008;    ch1->MaxOutput=2000;    ch1->DeadBandGain=1;    ch1->DeadBandRange=0;    ch1->InputChan0=1;    ch1->InputChan1=1;    ch1->OutputChan0=1;    ch1->OutputChan1=1;    ch1->MasterAxis=-1;    ch1->LimitSwitchOptions=0x103;    ch1->LimitSwitchNegBit=136;    ch1->LimitSwitchPosBit=136;    ch1->SoftLimitPos=1e+009;    ch1->SoftLimitNeg=-1e+009;    ch1->InputGain0=1;    ch1->InputGain1=1;    ch1->InputOffset0=0;    ch1->InputOffset1=0;    ch1->OutputGain=1;    ch1->OutputOffset=0;    ch1->SlaveGain=1;    ch1->BacklashMode=BACKLASH_OFF;    ch1->BacklashAmount=0;    ch1->BacklashRate=0;    ch1->invDistPerCycle=1;    ch1->Lead=0;    ch1->MaxFollowingError=10000;    ch1->StepperAmplitude=250;    ch1->iir[0].B0=1;    ch1->iir[0].B1=0;    ch1->iir[0].B2=0;    ch1->iir[0].A1=0;    ch1->iir[0].A2=0;    ch1->iir[1].B0=1;    ch1->iir[1].B1=0;    ch1->iir[1].B2=0;    ch1->iir[1].A1=0;    ch1->iir[1].A2=0;    ch1->iir[2].B0=0.0166094;    ch1->iir[2].B1=0.0332189;    ch1->iir[2].B2=0.0166094;    ch1->iir[2].A1=1.60679;    ch1->iir[2].A2=-0.673229;        EnableAxisDest(1,0);            EnableAxisDest(1,ch1->Position);    DefineCoordSystem(1,-1,-1,-1);        Pos = chan[MPG_INPUT_AXIS].Position;    for (;;)    {        NewPos = chan[MPG_INPUT_AXIS].Position;        Change1 = NewPos - Pos;        Pos = NewPos;        if (ReadBit(ENABLE_MPG)) // if button pressed ignore the encoder.            Change1 = 0;        else if (ReadBit(FACTOR1))  // is X1 selected?            Factor = 2;        else if (ReadBit(FACTOR10))  // is X10 selected?            Factor = 20;        else if (ReadBit(FACTOR100))  // is X100 selected?            Factor = 200;        else                               Factor = 0.0;        if (ReadBit(SELECTX))  // is x selected?            Axis=0;        else if (ReadBit(SELECTY))  // is y selected?            Axis=1;        else if (ReadBit(SELECTZ))  // is z selected?            Axis=2;        // check if the Axis just changed or we have been         // converging to the target for a long time        if (Axis != LastAxis ||             (InMotion && Time_sec() > LastChangeTime+FINAL_TIME))        {            if (InMotion)                Move(LastAxis,Target);  //finalize any motion                LastAxis = Axis;            InMotion = FALSE;        }                if (Change1) // did we move?        {            if (!InMotion) Target = chan[Axis].Dest;            Target += Change1 * Factor;            MoveExp(Axis,Target,TAU);  // note: contains a WaitNextTimeSlice            LastChangeTime = Time_sec();            InMotion=TRUE;        }        else        {            WaitNextTimeSlice();        }            }        return 0;}


Group: DynoMotion Message: 9962 From: lovethebuzz69 Date: 8/13/2014
Subject: Re: MPG question
Hi Tom,

Sorry about the screwed up post.

Everything looked find when I pasted in the code.

Anyway, ch1 is my X axis. For some reason ch0 on my Kanalog does not work.

Well, now I think I see the problem. As soon as you said

"As coded to move Axis 1 SELECTY (Input bit 129) would need to be active.

The code says:

if (ReadBit(SELECTX)) // is x selected?
Axis=0;
else if (ReadBit(SELECTY)) // is y selected?
Axis=1;
else if (ReadBit(SELECTZ)) // is z selected?
Axis=2;

Since my Axis 1 is the X axis, these values need to be changed to match my setup. Correct?

I was activating Bit 128 expecting channel 1 to be the selected channel but the code is waiting for Bit 129 to move channel 1.

I will fix that tonight and give it a try.

Thanks

Rick
Group: DynoMotion Message: 9964 From: Tom Kerekes Date: 8/13/2014
Subject: Re: MPG question
Hi Rick,

In this case you should probably change to:

if (ReadBit(SELECTX)) // is x selected?
Axis=1;
else if (ReadBit(SELECTY)) // is y selected?
Axis=2;
else if (ReadBit(SELECTZ)) // is z selected?
Axis=3;

Regards
TK


From: "lovethebuzz69@... [DynoMotion]" <DynoMotion@yahoogroups.com>
To: DynoMotion@yahoogroups.com
Sent: Wednesday, August 13, 2014 9:53 AM
Subject: Re: [DynoMotion] MPG question

 
Hi Tom,

Sorry about the screwed up post.

Everything looked find when I pasted in the code.

Anyway, ch1 is my X axis. For some reason ch0 on my Kanalog does not work.

Well, now I think I see the problem. As soon as you said

"As coded to move Axis 1 SELECTY (Input bit 129) would need to be active.

The code says:

if (ReadBit(SELECTX)) // is x selected?
Axis=0;
else if (ReadBit(SELECTY)) // is y selected?
Axis=1;
else if (ReadBit(SELECTZ)) // is z selected?
Axis=2;

Since my Axis 1 is the X axis, these values need to be changed to match my setup. Correct?

I was activating Bit 128 expecting channel 1 to be the selected channel but the code is waiting for Bit 129 to move channel 1.

I will fix that tonight and give it a try.

Thanks

Rick